#ifndef _WX_STRCONV_H_
#define _WX_STRCONV_H_

#include "wx/defs.h"
#include "wx/wxchar.h"
#include "wx/buffer.h"

#ifdef __DIGITALMARS__
#include "typeinfo.h"
#endif

#if defined(__VISAGECPP__) && __IBMCPP__ >= 400
    #error mmmm
#  undef __BSEXCPT__
#endif

#include <stdlib.h>

#if wxUSE_WCHAR_T

#define wxCONV_FAILED ((size_t)-1)
#define wxNO_LEN ((size_t)-1)

class wxMBConv {
  public:
    virtual size_t ToWChar( wchar_t *dst, size_t dstLen,
                            const char *src, size_t srcLen = wxNO_LEN ) const;

    virtual size_t FromWChar( char *dst, size_t dstLen,
                              const wchar_t *src, size_t srcLen = wxNO_LEN ) const;
    const wxWCharBuffer cMB2WC( const char *in ) const;
    const wxCharBuffer cWC2MB( const wchar_t *in ) const;
    const wxWCharBuffer
    cMB2WC( const char *in, size_t inLen, size_t *outLen ) const;
    const wxCharBuffer
    cWC2MB( const wchar_t *in, size_t inLen, size_t *outLen ) const;
    const wxWCharBuffer cMB2WX( const char *psz ) const { return cMB2WC( psz ); }
    const wxCharBuffer cWX2MB( const wchar_t *psz ) const { return cWC2MB( psz ); }
    const wchar_t* cWC2WX( const wchar_t *psz ) const { return psz; }
    const wchar_t* cWX2WC( const wchar_t *psz ) const { return psz; }
    virtual size_t GetMBNulLen() const { return 1; }
    static size_t GetMaxMBNulLen() { return 4 /* for UTF-32 */; }


    virtual size_t MB2WC( wchar_t *out, const char *in, size_t outLen ) const;
    virtual size_t WC2MB( char *out, const wchar_t *in, size_t outLen ) const;
    virtual wxMBConv *Clone() const = 0;
    virtual ~wxMBConv();
};

class wxMBConvLibc : public wxMBConv {
  public:
    virtual size_t MB2WC( wchar_t *outputBuf, const char *psz, size_t outputSize ) const;
    virtual size_t WC2MB( char *outputBuf, const wchar_t *psz, size_t outputSize ) const;

    virtual wxMBConv *Clone() const { return new wxMBConvLibc; }
};

class wxConvBrokenFileNames : public wxMBConv {
  public:
    wxConvBrokenFileNames( const wxChar *charset );
    wxConvBrokenFileNames( const wxConvBrokenFileNames& conv )
      : wxMBConv(),
        m_conv( conv.m_conv ? conv.m_conv->Clone() : NULL ) {
    }
    virtual ~wxConvBrokenFileNames() { delete m_conv; }

    virtual size_t MB2WC( wchar_t *out, const char *in, size_t outLen ) const {
      return m_conv->MB2WC( out, in, outLen );
    }

    virtual size_t WC2MB( char *out, const wchar_t *in, size_t outLen ) const {
      return m_conv->WC2MB( out, in, outLen );
    }

    virtual size_t GetMBNulLen() const {
      return m_conv->GetMBNulLen();
    }

    virtual wxMBConv *Clone() const { return new wxConvBrokenFileNames( *this ); }

  private:
    wxMBConv *m_conv;

    DECLARE_NO_ASSIGN_CLASS( wxConvBrokenFileNames )
};

class wxMBConvUTF7 : public wxMBConv {
  public:
    virtual size_t MB2WC( wchar_t *outputBuf, const char *psz, size_t outputSize ) const;
    virtual size_t WC2MB( char *outputBuf, const wchar_t *psz, size_t outputSize ) const;

    virtual wxMBConv *Clone() const { return new wxMBConvUTF7; }
};

class wxMBConvUTF8 : public wxMBConv {
  public:
    enum {
      MAP_INVALID_UTF8_NOT = 0,
      MAP_INVALID_UTF8_TO_PUA = 1,
      MAP_INVALID_UTF8_TO_OCTAL = 2
    };

    wxMBConvUTF8( int options = MAP_INVALID_UTF8_NOT ) : m_options( options ) { }
    virtual size_t MB2WC( wchar_t *outputBuf, const char *psz, size_t outputSize ) const;
    virtual size_t WC2MB( char *outputBuf, const wchar_t *psz, size_t outputSize ) const;

    virtual wxMBConv *Clone() const { return new wxMBConvUTF8( m_options ); }

  private:
    int m_options;
};

class wxMBConvUTF16Base : public wxMBConv {
  public:
    enum { BYTES_PER_CHAR = 2 };

    virtual size_t GetMBNulLen() const { return BYTES_PER_CHAR; }

  protected:
    static size_t GetLength( const char *src, size_t srcLen );
};

class wxMBConvUTF16LE : public wxMBConvUTF16Base {
  public:
    virtual size_t ToWChar( wchar_t *dst, size_t dstLen,
                            const char *src, size_t srcLen = wxNO_LEN ) const;
    virtual size_t FromWChar( char *dst, size_t dstLen,
                              const wchar_t *src, size_t srcLen = wxNO_LEN ) const;
    virtual wxMBConv *Clone() const { return new wxMBConvUTF16LE; }
};

class wxMBConvUTF16BE : public wxMBConvUTF16Base {
  public:
    virtual size_t ToWChar( wchar_t *dst, size_t dstLen,
                            const char *src, size_t srcLen = wxNO_LEN ) const;
    virtual size_t FromWChar( char *dst, size_t dstLen,
                              const wchar_t *src, size_t srcLen = wxNO_LEN ) const;
    virtual wxMBConv *Clone() const { return new wxMBConvUTF16BE; }
};

class wxMBConvUTF32Base : public wxMBConv {
  public:
    enum { BYTES_PER_CHAR = 4 };

    virtual size_t GetMBNulLen() const { return BYTES_PER_CHAR; }

  protected:
    static size_t GetLength( const char *src, size_t srcLen );
};

class wxMBConvUTF32LE : public wxMBConvUTF32Base {
  public:
    virtual size_t ToWChar( wchar_t *dst, size_t dstLen,
                            const char *src, size_t srcLen = wxNO_LEN ) const;
    virtual size_t FromWChar( char *dst, size_t dstLen,
                              const wchar_t *src, size_t srcLen = wxNO_LEN ) const;
    virtual wxMBConv *Clone() const { return new wxMBConvUTF32LE; }
};

class wxMBConvUTF32BE : public wxMBConvUTF32Base {
  public:
    virtual size_t ToWChar( wchar_t *dst, size_t dstLen,
                            const char *src, size_t srcLen = wxNO_LEN ) const;
    virtual size_t FromWChar( char *dst, size_t dstLen,
                              const wchar_t *src, size_t srcLen = wxNO_LEN ) const;
    virtual wxMBConv *Clone() const { return new wxMBConvUTF32BE; }
};

#include "wx/fontenc.h"

class wxCSConv : public wxMBConv {
  public:
    wxCSConv( const wxChar *charset );
    wxCSConv( wxFontEncoding encoding );

    wxCSConv( const wxCSConv& conv );
    virtual ~wxCSConv();
    wxCSConv& operator=( const wxCSConv& conv );
    virtual size_t ToWChar( wchar_t *dst, size_t dstLen, const char *src, size_t srcLen = wxNO_LEN ) const;
    virtual size_t FromWChar( char *dst, size_t dstLen, const wchar_t *src, size_t srcLen = wxNO_LEN ) const;
    virtual size_t MB2WC( wchar_t *outputBuf, const char *psz, size_t outputSize ) const;
    virtual size_t WC2MB( char *outputBuf, const wchar_t *psz, size_t outputSize ) const;
    virtual size_t GetMBNulLen() const;
    virtual wxMBConv *Clone() const { return new wxCSConv( *this ); }
    void Clear();
    bool IsOk() const;
  private:

    void Init();


    void CreateConvIfNeeded() const;
    wxMBConv *DoCreate() const;
    void SetName( const wxChar *charset );
    wxChar *m_name;
    wxFontEncoding m_encoding;


    wxMBConv *m_convReal;
    bool m_deferred;
};

extern wxMBConv& wxConvLibc;


extern wxCSConv& wxConvISO8859_1;
extern wxMBConvUTF7& wxConvUTF7;
extern wxMBConvUTF8& wxConvUTF8;
extern wxMBConv * wxConvFileName;

#define wxConvFile (*wxConvFileName)

extern wxMBConv * wxConvCurrent;
extern wxCSConv& wxConvLocal;
extern wxMBConv * wxConvUI;

#ifdef WORDS_BIGENDIAN
typedef wxMBConvUTF16BE wxMBConvUTF16;
typedef wxMBConvUTF32BE wxMBConvUTF32;
#else
typedef wxMBConvUTF16LE wxMBConvUTF16;
typedef wxMBConvUTF32LE wxMBConvUTF32;
#endif

#define wxMBFILES 1

#if wxMBFILES && wxUSE_UNICODE
#define wxFNCONV(name) wxConvFileName->cWX2MB(name)
#define wxFNSTRINGCAST wxMBSTRINGCAST
#else
#if defined( __WXOSX__ ) && wxMBFILES
#define wxFNCONV(name) wxConvFileName->cWC2MB( wxConvLocal.cWX2WC(name) )
#else
#define wxFNCONV(name) name
#endif
#define wxFNSTRINGCAST WXSTRINGCAST
#endif

#else

class wxMBConv {
  public:
    const char* cMB2WX( const char *psz ) const { return psz; }
    const char* cWX2MB( const char *psz ) const { return psz; }
    wxMBConv *Clone() const { return NULL; }
};

#define wxConvFile wxConvLocal
#define wxConvUI wxConvCurrent

typedef wxMBConv wxCSConv;

extern WXDLLIMPEXP_DATA_BASE( wxMBConv ) wxConvLibc,
       wxConvLocal,
       wxConvISO8859_1,
       wxConvUTF8;
extern WXDLLIMPEXP_DATA_BASE( wxMBConv * ) wxConvCurrent;

#define wxFNCONV(name) name
#define wxFNSTRINGCAST WXSTRINGCAST

#endif

#define wxConvertWX2MB(s)   wxConvCurrent->cWX2MB(s)
#define wxConvertMB2WX(s)   wxConvCurrent->cMB2WX(s)

extern wxWCharBuffer wxSafeConvertMB2WX( const char *s );
extern wxCharBuffer wxSafeConvertWX2MB( const wchar_t *ws );


#endif

